﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO;
using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;

namespace System.Windows.Media.DirectShow.Ogg
{
    public class DSOggStream : IPhysicalOggStream
    {

        private MemoryStream stream = new MemoryStream();
        private Dictionary<int, LogicalOggStream> logicalStreams = new Dictionary<int, LogicalOggStream>();
        private int pageNumber = 0;
        private List<OggPage> startPages = new List<OggPage>(3);

        #region IPhysicalOggStream Members

        public System.Collections.ICollection LogicalStreams
        {
            get { return (pageNumber >= 3) ? logicalStreams.Values : (ICollection)new ILogicalOggStream[0]; }
        }

        public OggPage GetOggPage(int index)
        {
            if (index - 1 > pageNumber)
                throw new NotSupportedException("Seek not supported yet");

            OggPage op = null;
            if (startPages.Count == 0)
            {
                if (FillOggPage())
                {
                    op = startPages[0];
                    startPages.Clear();
                }
            }
            else
            {
                op = startPages[0];
                startPages.RemoveAt(0);
            }

            return op;
        }

        private bool FillOggPage()
        {
            long position = stream.Position;
            OggPage op = GetNextPage(false);

            // Page too lenght or null
            if (op == null || position + op.TotalLength > stream.Length)
            {
                stream.Position = position;
                return false;
            }

            // Get logical stream
            LogicalOggStream los = null;
            if (!logicalStreams.TryGetValue(op.StreamSerialNumber, out los))
            {
                los = new LogicalOggStream(this, op.StreamSerialNumber);
                logicalStreams.Add(op.StreamSerialNumber, los);
            }

            los.AddGranulePosition(op.AbsoluteGranulePosition);
            logicalStreams[op.StreamSerialNumber].AddPageNumberMapping(pageNumber);

            pageNumber++;

            startPages.Add(op);

            byte[] buffer = stream.GetBuffer();
            long diff = (stream.Length - stream.Position);

            // Traslate buffer to the begin
            Buffer.BlockCopy(buffer, (int)stream.Position, buffer, 0, (int)diff);
            stream.SetLength(diff);
            stream.Position = 0;

            return true;
        }

        private OggPage GetNextPage(bool skipData)
        {
            return OggPage.Create(stream, skipData);
        }

        public bool Open
        {
            get { return true; }
        }

        public void Close()
        {
        }

        public long Time
        {
            set {  }
        }

        #endregion

        internal void Append(IMediaSample sample)
        {
            long p = stream.Position;
            stream.Position = stream.Length;
            stream.Write(sample.Data, 0, (int)sample.Length);
            stream.Position = p;

            if (logicalStreams.Count == 0)
            {
                while (FillOggPage())
                { }
            }
        }
    }
}
